package md.specialEqp.fee;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import md.specialEqp.inspect.Detail;
import md.specialEqp.type.PipingUnit;
import md.system.User;
import org.fjsei.yewu.filter.Uunode;
import org.fjsei.yewu.util.Tool;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.springframework.util.StringUtils;

import jakarta.persistence.*;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**收费项目 明细。
 * 一个Isp有多条Charging收费明细的。有后端自动生成，也有前端添加的。
 * 上级的Task实体也能直接 关联增加多条Charging;
 * 管道单元依据长度聚合的收费项：关联哪一些单元依据Isp的任务Eqp.Task关联选择单元；保持一致性。
*/

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Charging implements Uunode {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    /**直接依附于Detail，而不是挂接Isp；收费明细属于短期数据，物理存储期限需求短。
     * 管道收费特别：
     */
    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn
    private Detail  detail;

    /**项目编码。 有层次，4位符号。
     * 前端后端或者异构系统的共享编码。一个业务下：code唯一性，不能重复。
     * 收费明细项目表: 单一个挂接Isp的关联页面显示：应该能够一次性获取全量收费明细项: 数量不能太多。
     */
    private String code;
    /*项目名称。 给出收费单一项简要依据名称
     private String name;  名称脱离：前端系统根据code来认定给出名称的。
     amount= 项目标准/单位 * mnum;
     收费单位、标准说明：前端给出解释的。 后端代码隐含。
    */

    /**自定义收费：理由说明
     * mod=6: 必须给出说明，详细计算差额。
     * 后端自动计算的也允许设置memo：用于说明计费依据关键参数数值，主要是有问题的的计费参数：直接报给前端显示。
     */
    @Column(length =2000)
    private String  memo;

    //用double, 保留小数最多不超过3位, 勉强应付几百个亿, 那对于金融, 科学计算领域,不能满足需求了！ BigDecimail;
    /**金额(mod!=9的)， 正负数；
     * mod=9也能表示 加收减收 乘数系数；乘法可交换;
     * */
    private Double  amount;
    /**是否是人工添加的项目依据。 尽量都能自动计算，参数选择的进入业务参数也能自动计算。
     * mod=8的有些会是乘数， mod=9一定都是乘数的。
     * 把收费规则集合划分为两个大集合{自动计算规则的项目}U{人工选择的项目}，不允许中间摇摆的。尽量使用Detail参数进行状态选择管理。
     * */
    @Column(nullable=false)
    private Boolean  manual;
    /**收费条目性质； 指示最终收费金额计算的插入位置。
     * FEE_MOD=1 ,2,  8, 9,  6， 5： 增加了mod=5,=6；
     * mod=6是最顶层最后的加减数额；"其它加收、减收条款"。
     * mod=5是来源自这个需求"检验费低于500元的按500元收取","EXTRAFEE_ID":"109"；｛mod1+mod2+mod8总收费>=500｝?特殊插入计算点位! 假如<500才有效，500才有效，>=500抛弃前端不显示。
     *收费确认时刻，再来修订mod=5特别收费项目的去留。触发fee_mod=5 最低的保底金额=500；
     * 最后结果：Isp总金额==([mod1+mod2 +mod8(mod1*factor) ?$mod5?<500]) *mod9 +mod6;
     * 涉及到了mod1各项目收费的参数被修改的直接作废未终结任务的Isp的收费依据。重置收费确认标记。管道单元有涉及Task的。
     * 重新计算收费：{自动计算规则的项目}删除重加，{人工选择的项目}不动，有矛盾的需人工干预。
     * 重新计算收费：有mod6的需要特别提醒！是否要改？  mod=6=9必然是人工选择的； mod=1必然是自动计算规则的；
     mod关键字不能用！JPA无法生成表;
     【修正】mod1 全部是自动计算的，允许没有mod1收费项目，允许多于1条的mod1收费项;  mod6也允许多条。
     * */
    private Byte  fm;
    /**乘数，几米 几个 几平方； 默认是=1; 指出倍数关系方便推算；有些可能前端需加固定基数说明。
     * 正常情况：  amount == 项目标准/单位 * mnum;
     * 加固定基数的特例情况： amount == 说明基数+ (标准/单位 * mnum);
     * 特例有个： EXTRAFEE_ID":"121"+"122",&&CHAADVMOM>10000", RS_EXPR":"(srcPrice*2.5)/100",RS_TIME":"(CHAADVMOM-10000)/50", ?合并@
     *  /上面特例有一个，需要前端给出解释，否则不知道为何：amount !== 项目标准/单位 * mnum;
     * 特例: 机械式停车设备定期检验，停车位超过（含）20个" FEE_COD":"4172":RS_EXPR":"(BERNUM-19)*80+3040" FEE_STANDARD":"80"本例mnum=(BERNUM-19)；
     * 自动计算一般不用； 除非收费基数标准很简单明白的可以上 *=X。 若项目标准/单位@被乘数可变，说明乘数。
     * */
    private Double  mnum;

    /**管道装置底下的 哪一些单元 目前属于本收费规则选择中的；
     * 这些管道单元 pipus?.[leng]的长度合计=收费乘数=mnum；
      一个单元最多只能被一条同类别规则选择中。
      有的规则类别，所有Task归属管道单元都必须被点上。
      管道这类的规则 都是自动计算的。
     【注意】自动计算，清理收费Charging项目的时刻，关联的pipus数据也要一起删除，遗留垃圾数据。
     管道单元选择实际在派工之后｛有周期定期约定的还能自动归并同一个时间点附近：估算工作量派工｝，检验工作进行初期，依照客户需求：选完了才能够计算收费。
     */
    @ManyToMany
    @JoinTable
    @org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region = "Fast")
    private List<PipingUnit> pipus;
    //若改Set<Authority>默认生成PRIMARY KEY (user_id ASC, authority_id ASC)组合主键,若是List默认生成rowid INT8 DEFAULT unique_rowid(),但已经建表的不会再变。


//    public String id() {
//        return Tool.toGlobalId(this.getClass().getSimpleName(), String.valueOf(this.id));
//    }

    public void fillFeeFe(String code, double amount, int fm, Double mnum,String memo) {
        this.manual=true;
        this.code=code;
        this.amount=amount;
        this.fm=(byte)fm;
        this.mnum=mnum;
        if(StringUtils.hasText(memo))   this.memo=memo;
    }
}


/* @数据库修改脚本：
CREATE INDEX charging_detail_id_index ON public.charging USING btree (detail_id ASC);
    中间表：（需单一个事务之内完成的）
    BEGIN;
    ALTER TABLE public.charging_pipingunit DROP CONSTRAINT charging_pipingunit_pkey;
    ALTER TABLE public.charging_pipingunit ADD CONSTRAINT "primary" PRIMARY KEY (charging_id, pipus_id);
    COMMIT;
    alter table public.charging_pipingunit  drop column rowid;
* */